package core.subcontrollers;

import java.awt.Color;

import misc.MArrayList;
import boundary.UI;
import dto.Field;
import dto.Player;
import dto.PropertyField;
import entity.fields.Jail;
import entity.fields.properties.Street;
import entity_controllers.options.BuyHouseOption;
import entity_controllers.options.SellHouseOption;
import entity_controllers.options.ShakeMoveOption;
import entity_controllers.options.effects.MoveEffect;
import ie.FieldBoard;
import entity.Account;

public class SubController {

	/**
	 * @param player
	 * 
	 *           This method is used when a player sells buildings. It's mainly using 2 lists, 1 list of streets with buildings that a player owns and 1 list to simulate the options the player got -
	 *           the streets with houses and 'cancel'. The player is repeatedly asked to sell houses until there are no streets left with buildings or 'cancel' has been chosen.
	 */
	public static void sellHouse(Player player) {

		PropertyField[] properties = player.getAccount().getProperties();
		MArrayList<Street> streetsList = new MArrayList<Street>();
		MArrayList<String> optionsList = new MArrayList<String>();
		// add cancel as first option
		optionsList.add("Tilbage");
		// for each property
		for (int i = 0; i < properties.length; i++) {
			// if property is a street
			if (properties[i].getClass().equals(Street.class)) {
				// if street has buildings
				if (((Street) properties[i]).getBuildings() > 0) {
					// add street to streetsList and street name to optionsList
					streetsList.add((Street) properties[i]);
					optionsList.add(properties[i].getName());
				}
			}
		}

		// do while there are streets with buildings
		while (!streetsList.isEmpty()) {
			Street selectedStreet = selectStreet(streetsList, optionsList);
			if (selectedStreet == null)
				return;
			int buildings = selectedStreet.getBuildings();
			if (buildings == 5) {
				player.getAccount().addBalance((selectedStreet.getPrice() * buildings) / 2);
				selectedStreet.setBuildings(0);
			} else {
				player.getAccount().addBalance(selectedStreet.getPrice() / 2);
				selectedStreet.setBuildings(buildings - 1);
			}
			if (selectedStreet.getBuildings() == 0) {
				streetsList.remove(selectedStreet);
				optionsList.remove(selectedStreet.getName());
			}
			UI.get().showPlayer(player);
		}
		((Account) player.getAccount()).getOM().getOption(SellHouseOption.class).disable();
	}

	public static void buyHouse(Player player, FieldBoard fieldBoard) {
		MArrayList<Street> streetsList = new MArrayList<Street>();
		while (streetConstruction(player, fieldBoard, streetsList)) {

			// streetGroupsArray
			// streetsList
			Street[] streets = streetsList.getArray();
			MArrayList<String> optionsList = new MArrayList<String>();
			// add cancel as first option
			optionsList.add("Cancel");
			// for each property
			for (int i = 0; i < streets.length; i++) {
				optionsList.add(streets[i].getName());
			}

			Street selectedStreet = selectStreet(streetsList, optionsList);
			if (selectedStreet == null)
				return;
			selectedStreet.setBuildings(selectedStreet.getBuildings() + 1);
			player.getAccount().subBalance(selectedStreet.getHousePrice());
			streetsList = new MArrayList<Street>();
			UI.get().showPlayer(player);
			UI.get().showFields(fieldBoard.getFields());
		}
		((Account) player.getAccount()).getOM().getOption(BuyHouseOption.class).disable();
	}

	public static boolean streetConstruction(Player player, FieldBoard gameBoard, MArrayList<Street> streetsList) {
		// FIRST: create a list of street-groups and add owned streets into the relative street-groups.

		MArrayList<StreetGroup> streetGroups = new MArrayList<StreetGroup>();
		PropertyField[] properties = player.getAccount().getProperties();
		// for each property
		for (int i = 0; i < properties.length; i++) {
			// if property is a street
			if (properties[i].getClass().equals(Street.class)) {
				// if a street group exist with matching color
				Street street = (Street) properties[i];
				StreetGroup streetGroup = hasStreetGroup(street, streetGroups);
				if (streetGroup != null) {
					streetGroup.add(street);
				} else {
					streetGroups.add(new StreetGroup(street));
				}
			}
		}
		if (streetGroups.isEmpty())
			return false;
		System.out.println("HAS STREETGROUPS");
		// SECOND: remove all street-groups from the list that aren't full or already contains max buildings
		MArrayList<StreetGroup> tempStreetGroups = new MArrayList<StreetGroup>();
		StreetGroup[] streetGroupsArray = streetGroups.getArray();
		for (int i = 0; i < streetGroupsArray.length; i++) {
//			System.out.println(streetGroupsArray[i].getColor());
			if (streetGroupsArray[i].isFull(getAllStreets(gameBoard)))
				tempStreetGroups.add(streetGroupsArray[i]);
		}
		streetGroups = tempStreetGroups;
		if (streetGroups.isEmpty())
			return false;
		System.out.println("HAS FULL STREETGROUPS");
		// THIRD: create a new list with all streets in street-groups where buildings are affordable
		streetGroupsArray = streetGroups.getArray();
		for (int i = 0; i < streetGroupsArray.length; i++) {
			Street[] streetGroupArray = streetGroupsArray[i].getStreets();
			for (int j = 0; j < streetGroupArray.length; j++) {
				Street street = streetGroupArray[j];
				// if player can afford to build and if its possible to build on the street, add the street
				if (player.getAccount().hasAfford(street.getHousePrice()) && streetGroupsArray[i].streetCanBuild(street)) {
					System.out.println("ADD STREET " + street.getName());
					streetsList.add(street);
				}
			}
		}
		System.out.println("STREETSLIST SIZE " + streetsList.size());
		return !streetsList.isEmpty();
	}

	private static Street[] getAllStreets(FieldBoard gameBoard) {
		Field[] fields = gameBoard.getFields();
		MArrayList<Street> streetsList = new MArrayList<Street>();
		for (int i = 0; i < fields.length; i++) {
			if (fields[i].getClass().equals(Street.class))
				streetsList.add((Street) fields[i]);
		}
		return streetsList.getArray();
	}

	public static Street selectStreet(MArrayList<Street> streetsList, MArrayList<String> optionsList) {
		Street[] streets;
		// get arrays from arraylists
		streets = (Street[]) streetsList.getArray();
		String[] options = (String[]) optionsList.getArray();
		// get option from UI
		for (int i = 0; i < options.length; i++) {
			System.out.println("show options " + options[i]);
		}
		String option = UI.get().getSelectionMultiple("Vælg gade eller afbryd", options);
		// get the street that matches the selected option
		Street selectedStreet = null;
		for (int i = 0; i < streets.length; i++) {
			if (option.equals(streets[i].getName())) {
				selectedStreet = streets[i];
				break;
			}
		}
		return selectedStreet;
	}

	private static StreetGroup hasStreetGroup(Street street, MArrayList<StreetGroup> streetGroups) {
		if (streetGroups.isEmpty())
			return null;
		StreetGroup[] streetGroupsArray = streetGroups.getArray();
		for (int i = 0; i < streetGroupsArray.length; i++) {
			if (street.getColor().equals(streetGroupsArray[i].getColor()))
				return streetGroupsArray[i];
		}
		return null;
	}

	public static void setInJail(Player player, FieldBoard fieldBoard) {

		// find the Jail in the fieldBoard
		int jailIndex = 0;
		for (int f = 0; f < fieldBoard.getFields().length; f++) {
			if (fieldBoard.getField(f).getClass() == Jail.class && !((Jail) fieldBoard.getField(f)).isSendsToJail()) {
				jailIndex = f;
				break;
			}
		}

		// Move player to Jail Field
		player.setFieldIndex(jailIndex);
		UI.get().showPlayer(player);

		Account account = (Account) player.getAccount();

		account.getOM().getOption(ShakeMoveOption.class).disable();
		account.getOM().getOption(BuyHouseOption.class).disable();
		account.getOM().getOption(SellHouseOption.class).disable();

		account.getEM().getOption(MoveEffect.class).disable();

	}

	public static int getNumberOfStreetsWithSameColor(Street street, Street[] streets) {
		int numberOfSameColor = 0;
		Color color = street.getColor();
		
		if(streets == null)
			return 0;
		
		for (int i = 0; i < streets.length; i++) {
			if (streets[i].getColor().equals(color))
				numberOfSameColor++;
		}
		return numberOfSameColor;
	}

}
